/**
 * @Copyright: Copyright (c) 2017 Glodon, Inc. All rights reserved.
 */
package com.glodon.jcloud.increment.shorturl.security;

import cn.hutool.core.util.ObjectUtil;
import com.glodon.jcloud.common.security.AccessToken;
import com.glodon.jcloud.common.security.Strategy;
import com.glodon.jcloud.common.utils.URIUtil;
import com.glodon.jcloud.increment.common.cache.CommonCacheOperator;
import com.glodon.jcloud.signature.utils.SpringUtil;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Map;
import java.util.UUID;

/**
 * Glodon SDK API
 *
 * Token 工具类
 *
 * Create Date: 2017年8月16日 下午5:40:40
 *
 * @version:
 * @author: Terry.Li
 * @mail: lib-o@glodon.com
 */
public class TokenUtils {

	private static final Logger logger = LoggerFactory.getLogger(TokenUtils.class);

	private static CommonCacheOperator cache;

	private static Map<String, Map<String, String>> memCache = Maps.newConcurrentMap();
	private static Map<String, String> memCachedToken = Maps.newConcurrentMap();
	private static Map<String, String> memCachedRefreshToken = Maps.newConcurrentMap();

	private static CommonCacheOperator getCache() {
		if (ObjectUtil.isNull(cache)) {
			cache = SpringUtil.getBean(CommonCacheOperator.class);
		}
		return cache;
	}

	public static AccessToken createToken(Map<String, String> params) {
		if (null == params || params.isEmpty()) {
			throw new NullPointerException("valid token params.");
		}

		Strategy strategy = Strategy.randomStrategy();

		String token = strategy.encryption(UUID.randomUUID().toString());

//		String token = MD5.toMD5(UUID.randomUUID().toString());

//		String refreshToken = MD5.toMD5(UUID.randomUUID().toString()); 

		String refreshToken = strategy.encryption(UUID.randomUUID().toString());

		Long expireIn = getExpireIn().getTimeInMillis();

		doCache(token, expireIn, refreshToken, params);

		return new AccessToken(token, expireIn, refreshToken);
	}

	private static Calendar getExpireIn() {
		Calendar expire = Calendar.getInstance();
		expire.add(Calendar.SECOND, 1 * 60 * 60 * 2); // 两小时
//		expire.add(Calendar.SECOND, 1 * 60 * 60 * 12); // 12 小时
//		expire.add(Calendar.SECOND, 1 * 30); // 30秒
//		expire.add(Calendar.SECOND, 1 * 30); // 30秒
		return expire;
	}

	private static void doCache(String token, Long expireIn, String refreshToken, Map<String, String> params) {
		getCache().put(token, params, 1 * 60 * 60 * 24 * 181);
		getCache().put(refreshToken, params, 1 * 60 * 60 * 24 * 265);
	}

	private static String parseParams(Map<String, String> params) {
		Object[] keys = params.keySet().toArray();
		Arrays.sort(keys);
		StringBuffer sb = new StringBuffer();
		boolean first = true;
		for (Object key : keys) {
			if (first) {
				first = false;
			} else {
				sb.append("&");
			}
			sb.append(key).append("=");
			String value = params.get(key);
			sb.append(StringUtils.isBlank(value) ? StringUtils.EMPTY : URIUtil.encodeURIComponent(value));
		}
		return sb.toString();
	}

	public static Map<String, String> decodeToken(String token) throws Exception {
		Map<String, String> cached = getCache(token);
//		if (cached == null) {
//			throw new ApiException(ApiStatus.OAUTH2_TOKEN_EXPIRED);
//		}
		return cached;
	}

	private static Map<String, String> getCache(String token) {
		if (null != getCache()) {
		    return (Map<String, String>) getCache().get(token);
		} else {
			return memCache.get(token);
		}
	}

	private static boolean verifyExpireIn(Long _expireIn) {
		Calendar expireIn = Calendar.getInstance();
		expireIn.setTimeInMillis(_expireIn);

		Calendar currentTime = Calendar.getInstance();

        return currentTime.before(expireIn);
    }

}
